package edu.ucsd.cs110.mycity;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;

import org.jivesoftware.smack.Roster;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

import edu.ucsd.cs110.mycity.controller.CoordinateController;
import edu.ucsd.cs110.mycity.controller.ViewController;
import edu.ucsd.cs110.mycity.controller.XMPPController;
import edu.ucsd.cs110.mycity.model.data.AllFavorite;
import edu.ucsd.cs110.mycity.model.data.Buddy;
import edu.ucsd.cs110.mycity.model.data.BuddyFavorite;
import edu.ucsd.cs110.mycity.model.data.Favorite;
import edu.ucsd.cs110.mycity.model.data.FavoritesModel;
import edu.ucsd.cs110.mycity.model.data.GooglePlaces;
import edu.ucsd.cs110.mycity.model.data.Place;
import edu.ucsd.cs110.mycity.model.data.PlaceList;
import edu.ucsd.cs110.mycity.model.data.TRKPTCoordinate;
import edu.ucsd.cs110.mycity.services.ChatService;

public class MyCityMapActivity extends MapActivity implements LocationListener {

	private MapController mapController;
	private MapView mapView;
	private LocationManager locationManager;
	private GeoPoint currentPoint;
	public Location currentLocation = null;
	private MyOverlay currPos= null;
	private List<Buddy> buddyOverlays = null;
	private List<MyOverlay> cafeOverlays = null;
	public List<Favorite> myFav = null;
	private List<BuddyFavorite> buddyFav = null;
	private GooglePlaces googlePlaces;
	private Boolean addFavorite = false;
	private Button addFavoriteButton;
	private HashMap<Long,Boolean> favMap = new HashMap<Long,Boolean>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		buddyOverlays = new ArrayList<Buddy>();
		cafeOverlays = new ArrayList<MyOverlay>();
		setContentView(R.layout.activity_map);
		mapView = (MapView) findViewById(R.id.mapView);
		mapView.setBuiltInZoomControls(true);
		mapController = mapView.getController();
		mapController.setZoom(18);
		getLastLocation();
		drawCurrPositionOverlay();
		drawMyFav();
		drawBuddyFav();
		animateToCurrentLocation();
		ViewController.setMapScreen(this);
		Intent intent = new Intent(this, ChatService.class);
		this.startService(intent);
		addFavoriteButton = (Button) findViewById(R.id.addFavoriteButton);
		addFavoriteButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				if (addFavorite == false) {
					flipFavorite();
				} else {
					flipFavorite();
				}
			}
			
		});
		Log.i("MapActivity", "trying to start chat service");	
		Timer timer = new Timer();
		timer.schedule(new RefreshScreenTask(), 10000, 10000);
		timer.schedule(new SendLocationInfo(), 0, 30000);
	}

	class RefreshScreenTask extends TimerTask {

		@Override
		public void run() {
			favMap.clear();
			drawMyFav();
			drawBuddyFav();
		}
		
	}
	
	class SendLocationInfo extends TimerTask {

		@Override
		public void run() {
			new ChatService.SendLocationInfoTask().execute();
		}
		
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
	
	public boolean setFavorite() {
		return this.addFavorite;
	}
	
	public void flipFavorite() {
		this.addFavorite = !this.addFavorite;
		if ( this.addFavorite ) {
			addFavoriteButton.setText("Cancel");
		} else {
			addFavoriteButton.setText("Add Favorite");
		}
	}
	
	public void getLastLocation(){
		String provider = getBestProvider();
		currentLocation = locationManager.getLastKnownLocation(provider);
		if(currentLocation != null){
			setCurrentLocation(currentLocation);
		}
		else
		{
			Toast.makeText(this, "Location not yet acquired", Toast.LENGTH_LONG).show();
		}
	}
	public void animateToCurrentLocation(){
		if(currentPoint!=null){
			mapController.animateTo(currentPoint);
		}
	}
	public String getBestProvider(){
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		Criteria criteria = new Criteria();
		criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		String bestProvider = locationManager.getBestProvider(criteria, true);
		return bestProvider;
	}
	
	public void setCurrentLocation(Location location){
		int currLatitude = (int) (location.getLatitude()*1E6);
		int currLongitude = (int) (location.getLongitude()*1E6);
		currentPoint = new GeoPoint(currLatitude,currLongitude);
		currentLocation = new Location("");
		currentLocation.setLatitude(currentPoint.getLatitudeE6() / 1e6);
		currentLocation.setLongitude(currentPoint.getLongitudeE6() / 1e6);
		drawCurrPositionOverlay();
	}

	@Override
	public void onLocationChanged(Location location) {
		System.out.println("Location changed");
		setCurrentLocation(location);
		animateToCurrentLocation();
	}

	@Override
	protected void onResume() {
		super.onResume();
		MyCity.resume();
		locationManager.requestLocationUpdates(getBestProvider(), 1000, 1, this);
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		MyCity.pause();
		locationManager.removeUpdates(this);
	}

	@Override
	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub

	}

	public void drawCurrPositionOverlay(){
		List<Overlay> overlays = mapView.getOverlays();
		overlays.remove(currPos);
		Drawable marker = getResources().getDrawable(R.drawable.mylocation);
		currPos = new MyOverlay(marker,mapView);
		if(currentPoint!=null){
			OverlayItem overlayitem = new OverlayItem(currentPoint, "Me", "Here I am!");
			currPos.addOverlay(overlayitem);
			overlays.add(currPos);
			currPos.setCurrentLocation(currentLocation);
		}
		new LoadPlaces().execute();
	}
	
	public void addPin(GeoPoint point) {
		Drawable marker = getResources().getDrawable(R.drawable.favorite);
		final List<Overlay> overlays = mapView.getOverlays();
		final Favorite pin = new Favorite(marker,mapView);
		LinearLayout lila = new LinearLayout(this);
		lila.setOrientation(1); //1 is for vertical orientation
		final EditText input = new EditText(this); 
		input.setHint("Name");
		final EditText input1 = new EditText(this);
		input1.setHint("Description");
		lila.addView(input);
		lila.addView(input1);
		final GeoPoint thePoint = point;
		AlertDialog.Builder alert = new AlertDialog.Builder(this)
			.setTitle("Add Favorite")
			.setView(lila);
		alert.setPositiveButton("Add", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				String name = input.getText().toString();
				String description = input1.getText().toString();
				OverlayItem overlayitem = new OverlayItem(thePoint, name, description);
				pin.addOverlay(overlayitem);
				overlays.add(pin);
				Location l = new Location("");
				l.setLatitude(thePoint.getLatitudeE6() / 1E6);
				l.setLongitude(thePoint.getLongitudeE6() / 1E6);
				pin.setCurrentLocation(l);
				pin.setName(name);
				pin.setDescription(description);
				pin.setPoint(thePoint);
				pin.setVisible(false);
				FavoritesModel.put(pin);
			}
			
		});
		alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				
			}
		});
		alert.show();
	}
	
	public void drawMyFav() {
		new DrawMyFavorites().execute();
	}
	
	public class DrawMyFavorites extends AsyncTask<Void,Void,List<Favorite>> {

		@Override
		protected List<Favorite> doInBackground(Void... arg0) {
			Drawable marker = getResources().getDrawable(R.drawable.favorite);
			List<Favorite> l = FavoritesModel.getMyFavorites(marker, MyCityMapActivity.this.mapView);
			return l;
		}
		
		@Override
		protected void onPostExecute(List<Favorite> result) {
			Iterator<Favorite> iter = result.iterator();
			List<Overlay> overlays = mapView.getOverlays();
			Iterator<Overlay> i = overlays.iterator();
			while ( i.hasNext() ) {
				Overlay o = i.next();
				if (o instanceof Favorite) {
					i.remove();
				}
			}
			while (iter.hasNext()) {
				Favorite f = iter.next();
				String name = f.getName();
				String description = f.getDescription();
				GeoPoint geoPt = f.getPoint();
				Location l = new Location("");
				l.setLatitude(f.getLatSpanE6());
				l.setLongitude(f.getLonSpanE6());
				OverlayItem overlayitem = new OverlayItem(geoPt, name, description);
				f.addOverlay(overlayitem);
				favMap.put(f.getKey(), true);
				overlays.add(f);
			}
			super.onPostExecute(result);
		}
		
	}
	
	public void drawBuddyFav() {
		new DrawBuddyFavorites().execute();
	}

	public class DrawBuddyFavorites extends AsyncTask<Void,Void,List<BuddyFavorite>> {

		@Override
		protected List<BuddyFavorite> doInBackground(Void... arg0) {
			Drawable marker = getResources().getDrawable(R.drawable.buddy_favorite);
			ArrayList<BuddyFavorite> ret = new ArrayList<BuddyFavorite>();
			Collection<String> roster = XMPPController.getBuddies();
			for (String s : roster) {
				List<BuddyFavorite> l = FavoritesModel.getFavoritesFor(s, marker, mapView);
				ret.addAll(l);
			}
			return ret;
		}
		
		@Override
		protected void onPostExecute(List<BuddyFavorite> result) {
			Iterator<BuddyFavorite> iter = result.iterator();
			List<Overlay> overlays = mapView.getOverlays();
			Iterator<Overlay> i = overlays.iterator();
			while ( i.hasNext() ) {
				Overlay o = i.next();
				if (o.getClass() == BuddyFavorite.class) {
					i.remove();
				}
			}
			while (iter.hasNext()) {
				BuddyFavorite f = iter.next();
				String name = f.getName();
				String description = f.getDescription();
				GeoPoint geoPt = f.getPoint();
				Location l = new Location("");
				l.setLatitude(f.getLatSpanE6());
				l.setLongitude(f.getLonSpanE6());
				OverlayItem overlayitem = new OverlayItem(geoPt, name, description);
				f.addOverlay(overlayitem);
				favMap.put(f.getKey(), true);
				overlays.add(f);
			}
			drawEveryoneElseFavorites();
			super.onPostExecute(result);
		}
		
	}
	
	public void drawEveryoneElseFavorites() {
		new DrawEveryoneElseFavorites().execute();
	}
	
	public class DrawEveryoneElseFavorites extends AsyncTask<Void,Void,List<AllFavorite>> {

		@Override
		protected List<AllFavorite> doInBackground(Void... arg0) {
			Drawable marker = getResources().getDrawable(R.drawable.nonbuddy_favorite);
			List<AllFavorite> l = FavoritesModel.getAllFavorites(marker, mapView);
			return l;
		}
		
		@Override
		protected void onPostExecute(List<AllFavorite> result) {
			Iterator<AllFavorite> iter = result.iterator();
			List<Overlay> overlays = mapView.getOverlays();
			Iterator<Overlay> i = overlays.iterator();
			while ( i.hasNext() ) {
				Overlay o = i.next();
				if (o instanceof AllFavorite) {
					i.remove();
				}
			}
			while (iter.hasNext()) {
				AllFavorite f = iter.next();
				if (favMap.containsKey(f.getKey()))
					continue;
				String name = f.getName();
				String description = f.getDescription();
				GeoPoint geoPt = f.getPoint();
				Location l = new Location("");
				l.setLatitude(f.getLatSpanE6());
				l.setLongitude(f.getLonSpanE6());
				OverlayItem overlayitem = new OverlayItem(geoPt, name, description);
				f.addOverlay(overlayitem);
				overlays.add(f);
			}
			super.onPostExecute(result);
		}
		
	}
	
	public void drawBuddies() {
		List<Overlay> overlays = mapView.getOverlays();
		Iterator<Buddy> iter = buddyOverlays.iterator();
		while (iter.hasNext()) {
			Buddy o = iter.next();
			overlays.remove(o);
			buddyOverlays.remove(o);
		}
		Drawable marker = getResources().getDrawable(R.drawable.buddieslocation);
		Map<String,TRKPTCoordinate> m = CoordinateController.getCoordinates();
		Iterator<Entry<String,TRKPTCoordinate>> iter2 = m.entrySet().iterator();
		while (iter2.hasNext()) {
			Entry<String,TRKPTCoordinate> e = iter2.next();
			Log.i("Drawing", e.getKey());
			TRKPTCoordinate t = e.getValue();
			Buddy buddy = new Buddy(marker,mapView);
			OverlayItem overlayitem = new OverlayItem(t.getGeoPoint(),e.getKey(),"Click here to start chat");
			Roster roster = XMPPController.getRoster();
			String presence = roster.getPresence(e.getKey()).toString();
			if( !presence.substring(0,9).equals("available") ) {
				continue;
			}
			buddy.addOverlay(overlayitem);
			overlays.add(buddy);
			buddy.setCurrentLocation(t.getLocation());
			buddyOverlays.add(buddy);
			buddy.setUsername(e.getKey());
			buddy.setAct(this);
			buddy.dist(Math.abs(e.getValue().getLongtitude()-currentLocation.getLongitude())*111.0/1.6,Math.abs(e.getValue().getLatitude()-currentLocation.getLatitude())*111.0/1.6);
			if(buddy.isNear() && (buddy.isNear() != buddy.isPrevNear())) {
				NotificationFactory.createNearbyNotification(this, buddy.getUsername());
				SoundFacade.playNotificationSound(getApplicationContext());
				buddy.setPrevNear(buddy.isNear());
			}
			else
				buddy.setPrevNear(buddy.isNear());
		}
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == R.id.buddy_list) {
			Intent buddyListIntent = new Intent(MyCityMapActivity.this,BuddyListActivity.class);
			buddyListIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
			this.startActivity(buddyListIntent);
			return true;
		}
		Log.e("Menu","menu didn't work");
		return super.onOptionsItemSelected(item);
	}
	
	public void drawPOIs(PlaceList nearPlaces) {
		List<Overlay> overlays = mapView.getOverlays();
		Iterator<MyOverlay> iter = cafeOverlays.iterator();
		while ( iter.hasNext() ) {
			MyOverlay o = iter.next();
			overlays.remove(o);
			cafeOverlays.remove(o);
		}
		Drawable marker = getResources().getDrawable(R.drawable.restaurants);
		MyOverlay pOIs = new MyOverlay(marker, mapView);
		// loop through each place
		for (Place p : nearPlaces.results) {
			int lat = (int) (p.geometry.location.lat * 1e6);
			int lng = (int) (p.geometry.location.lng * 1e6);
			OverlayItem overlayItem = new OverlayItem(new GeoPoint(lat, lng),
					p.name, p.vicinity);
			pOIs.addOverlay(overlayItem);
			Log.d("POI", "Place: " + p.name+" "+lat+ " "+lng);
		}
		
		overlays.add(pOIs);
		pOIs.setCurrentLocation(currentLocation);
		cafeOverlays.add(pOIs);
	}

	/**
	 * Background Async Task to Load Google places
	 * */
	class LoadPlaces extends AsyncTask <String, String, PlaceList > {

		/**
		 * Before starting background thread Show Progress Dialog
		 * */
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}

		/**
		 * getting Places JSON
		 * */
		protected PlaceList doInBackground(String... args) {
			// creating Places class object
			googlePlaces = new GooglePlaces();
			PlaceList nearPlaces = null;
			try {
				// Separate your place types by PIPE symbol "|"
				// If you want all types places make it as null
				// Check list of types supported by google
				//
				String types = "cafe|restaurant"; // Listing places only cafes,
				// restaurants

				// Radius in meters - increase this value if you don't find any
				// places
				double radius = 2000; // 2000 meters

				if (currentLocation != null) {
					// get nearest places
					nearPlaces = googlePlaces.search(
							currentLocation.getLatitude(),
							currentLocation.getLongitude(), radius, types);
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
			return nearPlaces;
		}

		/**
		 * After completing background task show the data in UI Always use
		 * runOnUiThread(new Runnable()) to update UI from background thread,
		 * otherwise you will get error
		 * **/
		protected void onPostExecute(PlaceList nearPlaces) {
			//Log error
			if(nearPlaces == null )
				return;

			/**
			 * Updating parsed Places into LISTVIEW
			 * */
			// Get json response status
			String status = nearPlaces.status;

			// Check for all possible status
			if (status.equals("OK")) {
				// Successfully got places details
				if (nearPlaces.results != null) {
					drawPOIs(nearPlaces);
				}
			} else if (status.equals("ZERO_RESULTS")) {
				// Zero results found
				Toast.makeText(
						MyCityMapActivity.this,
						"Sorry no places found. Try to change the types of places",
						Toast.LENGTH_LONG).show();
			} else if (status.equals("UNKNOWN_ERROR")) {
				Toast.makeText(MyCityMapActivity.this,
						"Sorry unknown error occured.",
						Toast.LENGTH_LONG).show();
			} else if (status.equals("OVER_QUERY_LIMIT")) {
				Toast.makeText(
						MyCityMapActivity.this,
						"Sorry query limit to google places is reached",
						Toast.LENGTH_LONG).show();
			} else if (status.equals("REQUEST_DENIED")) {
				Toast.makeText(MyCityMapActivity.this,
						"Sorry error occured. Request is denied",
						Toast.LENGTH_LONG).show();
			} else if (status.equals("INVALID_REQUEST")) {
				Toast.makeText(MyCityMapActivity.this,
						"Sorry error occured. Invalid Request",
						Toast.LENGTH_LONG).show();
			} else {
				Toast.makeText(MyCityMapActivity.this,
						"Sorry error occured.", Toast.LENGTH_LONG)
						.show();
			}
		}

	}

}
